#include "head.hpp"

using namespace std;

string str_utf16le_to_utf8(const char *utf16Str, size_t len)
{
    /* UTF-8是多字节字符串(multibyte string)，而unicode是宽字符字符串(wchar_string)
    C++11提供了wstring_convert类(<codecvt>头文件)，支持wchar_t string和multibyte string的互相转换
    其中codecvt_utf8可以提供UTF-8的编码规则*/

    wstring_convert<codecvt_utf8_utf16<wchar_t>> converter;
    wstring utf16le_wstr(reinterpret_cast<const wchar_t *>(utf16Str), len / sizeof(wchar_t));
    return converter.to_bytes(utf16le_wstr);
}

wstring str_utf8_to_unicode(const string &str)
{
    /* UTF-8是多字节字符串(multibyte string)，而unicode是宽字符字符串(wchar_string)
    C++11提供了wstring_convert类(<codecvt>头文件)，支持wchar_t string和multibyte string的互相转换
    其中codecvt_utf8可以提供UTF-8的编码规则*/

    wstring_convert<codecvt_utf8<wchar_t>> wcv;
    return wcv.from_bytes(str);
}

string str_utf8_to_gpk(const char *uft8_str)
{
    int len = MultiByteToWideChar(CP_UTF8, 0, uft8_str, -1, nullptr, 0);
    wchar_t *wszGBK = new wchar_t[len + 1];
    memset(wszGBK, 0, len * 2 + 2);
    MultiByteToWideChar(CP_UTF8, 0, uft8_str, -1, wszGBK, len);
    len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, nullptr, 0, nullptr, nullptr);
    char *szGBK = new char[len + 1];
    memset(szGBK, 0, len + 1);
    WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, nullptr, nullptr);
    string str_tmp(szGBK);
    if (wszGBK)
        delete[] wszGBK;
    if (szGBK)
        delete[] szGBK;
    return str_tmp;
}

string str_gpk_to_utf8(const char *gpk_str)
{
    int len = MultiByteToWideChar(CP_ACP, 0, gpk_str, -1, nullptr, 0);
    wchar_t *wstr = new wchar_t[len + 1];
    memset(wstr, 0, len + 1);
    MultiByteToWideChar(CP_ACP, 0, gpk_str, -1, wstr, len);
    len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr);
    char *str = new char[len + 1];
    memset(str, 0, len + 1);
    WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, nullptr, nullptr);
    string str_tmp = str;
    if (wstr)
        delete[] wstr;
    if (str)
        delete[] str;
    return str_tmp;
}



bool utf16le_to_utf8(const string &file, const string &output)
{
    ifstream ifs(file, ios::in | ios::binary);
    ofstream ofs(output, ios::out | ios::binary);

    ifs.seekg(0, ios::end);
    size_t file_size = ifs.tellg();
    ifs.seekg(0, ios::beg);

    char *utf16le_data = new char[file_size];
    ifs.read(utf16le_data, file_size);

    wstring_convert<codecvt_utf8_utf16<wchar_t>> converter;
    wstring utf16le_wstr(reinterpret_cast<const wchar_t *>(utf16le_data), file_size / sizeof(wchar_t));
    string utf8_str = converter.to_bytes(utf16le_wstr);

    utf8_str = utf8_str.substr(3);

    utf8_str = str::replace(utf8_str,"\r\n","\n");
    // for (size_t i = 0; i < utf8_str.size() - 1; ++i)
    // {
    //     if (utf8_str[i] == '\r' && utf8_str[i + 1] == '\n')
    //     {
    //         utf8_str.erase(i, 1);
    //         --file_size;
    //         --i;
    //     }
    // }
    ofs << utf8_str;

    delete[] utf16le_data;

    ifs.close();
    ofs.close();
    return 0;
}

bool utf16le_to_utf8bom(const string &file, const string &output)
{
    ifstream ifs(file, ios::in | ios::binary);
    ofstream ofs(output, ios::out | ios::binary);

    ifs.seekg(0, ios::end);
    size_t file_size = ifs.tellg();
    ifs.seekg(0, ios::beg);

    char *utf16le_data = new char[file_size];
    ifs.read(utf16le_data, file_size);
    ifs.close();

    wstring_convert<codecvt_utf8_utf16<wchar_t>> converter;
    wstring utf16le_wstr(reinterpret_cast<const wchar_t *>(utf16le_data), file_size / sizeof(wchar_t));
    string utf8_str = converter.to_bytes(utf16le_wstr);

    // utf8_str = utf8_str.substr(3);

    // for (size_t i = 0; i < utf8_str.size() - 1; ++i)
    // {
    //     if (utf8_str[i] == '\r' && utf8_str[i + 1] == '\n')
    //     {
    //         utf8_str.erase(i, 1);
    //         --file_size;
    //         --i;
    //     }
    // }
    ofs << utf8_str;

    delete[] utf16le_data;

    ifs.close();
    ofs.close();
    return 0;
}

bool gpk_to_utf8(const std::string& file, const std::string& output)
{
    ifstream ifs(file, ios::in | ios::binary);
    ofstream ofs(output, ios::out | ios::binary);

    ifs.seekg(0, ios::end);
    size_t file_size = ifs.tellg();
    ifs.seekg(0, ios::beg);

    char *gpk_data = new char[file_size + 1];
    ifs.read(gpk_data, file_size);
    gpk_data[file_size] = '\0';
    ifs.close();

    string buf = str_gpk_to_utf8(gpk_data);

    ofs << buf;

    ifs.close();
    ofs.close();
    delete[] gpk_data;

    return true;
}

bool utf8_to_gpk(const std::string& file, const std::string& output)
{
    ifstream ifs(file, ios::in | ios::binary);
    ofstream ofs(output, ios::out | ios::binary);

    ifs.seekg(0, ios::end);
    size_t file_size = ifs.tellg();
    ifs.seekg(0, ios::beg);

    char *utf8_data = new char[file_size + 1];
    ifs.read(utf8_data, file_size);
    utf8_data[file_size] = '\0';
    ifs.close();

    string buf = str_utf8_to_gpk(utf8_data);

    ofs << buf;

    ifs.close();
    ofs.close();
    delete[] utf8_data;

    return true;
}

